<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
    <script>
        class State{
            constructor(level, actors, status){
                this.level = level;
                this.actors = actors;
                this.status = status;  // playing || lost || won
            }

            static start(level){
                return new State(level, level.startActors, "playing");
            }

            get player(){
                return this.actors.find(a => a.type === "player");
            }
        }

        class Vec{
            constructor(x, y){
                this.x = x;
                this.y = y;
            }
            plus(other){
                return new Vec(this.x + other.x, this.y + other.y);
            }
            times(factor){
                return new Vec(this.x*factor, this.y*factor);
            }
        }

        class Player{
            constructor(pos, speed){
                this.pos = pos;
                this.speed = speed;
            }

            get type(){
                return "player";
            }

            static create(pos){
                return new Player(pos.plus(new Vec(0, -0.5)), new Vec(0, 0));
            }
        }
        Player.prototype.size = new Vec(0.8, 1.5);

        class Lava {
            constructor(pos, speed, reset) {
                this.pos = pos;
                this.speed = speed;
                this.reset = reset;
            }
            get type() { return "lava"; }

            static create(pos, ch) {
                if (ch == "=") {
                    return new Lava(pos, new Vec(2, 0));
                } else if (ch == "|") {
                    return new Lava(pos, new Vec(0, 2));
                } else if (ch == "v") {
                    return new Lava(pos, new Vec(0, 3), pos);
                }
            }
        }
        Lava.prototype.size = new Vec(1, 1);

        class Coin {
            constructor(pos, basePos, wobble) {
                this.pos = pos;
                this.basePos = basePos;
                this.wobble = wobble;
            }
            get type() { return "coin"; }
            static create(pos) {
                let basePos = pos.plus(new Vec(0.2, 0.1));
                    return new Coin(basePos, basePos, Math.random() * Math.PI * 2);
            }
        }
        Coin.prototype.size = new Vec(0.6, 0.6);

        let simpleLevelPlan = `
            ......................
            ..#................#..
            ..#..............=.#..
            ..#.........o.o....#..
            ..#.@......#####...#..
            ..#####............#..
            ......#++++++++++++#..
            ......##############..
            ......................
        `;

        const levelChars = {
            ".": "empty", "#": "wall", "+": "lava",
            "@": Player, "o": Coin,
            "=": Lava, "|": Lava, "v": Lava
        };

        class Level{
            constructor(plan){
                let rows = plan.trim().split("\n").map( line => [...line.trim()] );  // [...l] == l.split("")
                this.height = rows.length;
                this.width = rows[0].length;
                this.startActors = [];
                this.rows = rows.map( (row, y) => {
                    return row.map((ch, x) => {
                        let type = levelChars[ch];
                        if(typeof type === "string") return type;
                        this.startActors.push(type.create(new Vec(x, y), ch));
                        return "empty";
                    })
                } )
            }
        }

        let simpleLevel = new Level(simpleLevelPlan);

    </script>
</body>
</html>